const Express = require('express')
const fs = require('fs')
const path = require('path')
const Logger = require('./src/utils/logger').Logger
const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD
const serialize = require('serialize-javascript');

async function createServer(
    root = process.cwd(),
    isProd = process.env.NODE_ENV === 'production'
) {
    try {
        const resolve = (p) => path.resolve(__dirname, p)

        const indexProd = isProd
            ? fs.readFileSync(resolve('./dist/client/index.html'), 'utf-8')
            : ''

        const manifest = isProd
            ? // @ts-ignore
            require(resolve('./dist/client/ssr-manifest.json'))
            : {}

        const app = new Express()

        /**
         * @type {import('vite').ViteDevServer}
         */
        let vite
        if (!isProd) {
            vite = await require('vite').createServer({
                root,
                logLevel: isTest ? 'error' : 'info',
                server: {
                    middlewareMode: 'ssr',
                    watch: {
                        // During tests we edit the files too fast and sometimes chokidar
                        // misses change events, so enforce polling for consistency
                        usePolling: true,
                        interval: 100
                    }
                }
            })
            app.use(vite.middlewares)
            // const middlewares = compose([main, vite.middlewares])
            // app.use(middlewares)
        } else {
            app.use(require('compression')())
            app.use(
                require('serve-static')(resolve('dist/client'), {
                    index: false
                })
            )
        }

        app.use("*", async (req, res) => {
            try {
                const url = req.originalUrl
                let template, render
                if (!isProd) {
                    template = fs.readFileSync(resolve('./index.html'), 'utf-8')
                    template = await vite.transformIndexHtml(url, template)
                    render = (await vite.ssrLoadModule(resolve('./src/entry-server.js'))).render
                } else {
                    template = indexProd
                    render = require('./dist/server/entry-server.js').render
                }
                // 调用服务端渲染方法，将vue组件渲染成dom结构，顺带分析出需要预加载的js，css等文件。
                const [appHtml, preloadLinks, store] = await render(url, manifest)
                // 新加 + 将服务端预取数据的store，插入html模板文件
                const state = ("<script>window.__INIT_STATE__" + "=" + serialize(store.state, {isJSON: true}) + "</script>");
                if (store.state.postInfo.title) {
                    template = template
                        .replace('<!--meta-title-->', store.state.postInfo.title)
                        .replace('<!--meta-keywords-->', '<meta name="keywords" content="' + store.state.postInfo.title + '" />')
                        .replace('<!--meta-description-->', '<meta name="description" content="' + store.state.postInfo.summary + '" />')
                } else {
                    template = template
                        .replace('<!--meta-title-->', '瑶瑶的梦中小屋')
                        .replace('<!--meta-keywords-->', '<meta name="keywords" content="瑶瑶的梦中小屋" />')
                        .replace('<!--meta-description-->', '<meta name="description" content="瑶瑶的梦中小屋,一个个人兴趣小站" />')

                }

                // 把html中的展位符替换成相对应的资源文件
                const html = template
                    .replace(`<!--preload-links-->`, preloadLinks)
                    .replace(`<!--app-html-->`, appHtml)
                    .replace(`<!--app-store-->`, state)
                res.status(200).set({'Content-Type': 'text/html'}).end(html)
            } catch (e) {
                vite && vite.ssrFixStacktrace(e)
                Logger.error(e.stack)
                res.status(500).end(e.stack)
            }
        })

        return {app, vite}
    } catch (error) {
        Logger.error(error)
    }
}

// 创建node服务器用作ssr
if (!isTest) {
    createServer().then(({app}) =>
        app.listen(5000, () => {
            Logger.info('http://localhost:5000')
        })
    )
}

// for test use
exports.createServer = createServer
